/**
 * 
 */
package com.onpositive.realmview.queryeditor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import com.onpositive.commons.platform.registry.IAdaptable2;
import com.onpositive.realmview.IRealmView;
import com.onpositive.realmview.model.IHasViews;
import com.onpositive.realmview.model.IViewGrouping;
import com.onpositive.realmview.model.filtering.BasicValueFilter;
import com.onpositive.realmview.model.filtering.IUIFilter;
import com.onpositive.realmview.model.realm.IRealmPosition;
import com.onpositive.realmview.queryeditor.ClassificationRealmPosition.Classification;
import com.onpositive.semantic.model.api.property.AggregateCalculator;
import com.onpositive.semantic.model.api.property.DefaultPropertyMetadata;
import com.onpositive.semantic.model.api.property.IProperty;
import com.onpositive.semantic.model.api.property.IPropertyMetaData;
import com.onpositive.semantic.model.api.property.adapters.ITextLabelProvider;
import com.onpositive.semantic.model.core.IKnownsImageObject;
import com.onpositive.semantic.model.realm.CodeAndMessage;

public class GroupNode implements IKnownsImageObject,
		IAdaptable2, IValidatable {
	/**
	 * 
	 */
	private final GroupingContentProvider groupingContentProvider;
	public IViewGrouping group;
	IViewGrouping childrenGrouping;
	public Object value;

	Object[] children;
	HashMap<String, Object> aggregates = new HashMap<String, Object>();
	GroupNode parent;

	public String toString() {
		return internalToString() + "(" + count + " items matched)";
	}

	public String getLongString() {
		if (parent != null) {
			return parent.getLongString() + "->" + internalToString();
		}
		return internalToString();
	}

	public IRealmView getRealmView() {
		return groupingContentProvider.realmView;
	}

	String internalToString() {
		if (groupName != null && groupName.length() != 0) {
			return groupName;
		}
		if (value == null || value.toString().length() == 0) {
			return "<None>";
		}
		if (adapter != null) {
			return adapter.getText(value);
		}
		return value + "";
	}

	int nodeVersion;

	public String getMemento() {
		StringBuilder bld = new StringBuilder();
		if (parent != null) {
			bld.append(parent.getMemento());
			bld.append(':');
		}
		bld.append(group.getId());
		bld.append('.');
		bld.append(value.toString());
		return bld.toString();
	}

	IProperty p;

	String groupName;

	public GroupNode(GroupingContentProvider groupingContentProvider,
			GroupNode parent, IViewGrouping string, Object q, String groupName,
			Object iRichDoc) {
		this.groupingContentProvider = groupingContentProvider;
		this.group = string;
		this.value = q;
		this.groupName = groupName;
		nodeVersion = this.groupingContentProvider.version;

		this.parent = parent;
		IProperty maybeGlobal = string.getProperty();
		IProperty shouldbecorrect = maybeGlobal.getPropertyProvider()
				.getProperty(iRichDoc, maybeGlobal.getId());
		// p = shouldbecorrect;
		// if (shouldbecorrect == null) {
		p = maybeGlobal;
		// }
		if (shouldbecorrect == null) {
			shouldbecorrect = maybeGlobal;
		}
		final IPropertyMetaData pmd = shouldbecorrect.getPropertyMetaData();
		adapter = pmd.getAdapter(ITextLabelProvider.class);

	}

	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((group == null) ? 0 : group.hashCode());
		result = prime * result + ((value == null) ? 0 : value.hashCode());
		return result;
	}

	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		GroupNode other = (GroupNode) obj;
		if (group == null) {
			if (other.group != null)
				return false;
		} else if (!group.equals(other.group))
			return false;
		if (value == null) {
			if (other.value != null)
				return false;
		} else if (!value.equals(other.value))
			return false;
		return true;
	}

	public Object[] getChildren() {
		if (nodeVersion != this.groupingContentProvider.version) {
			children = null;
			aggregates.clear();
		}

		if (children != null) {
			return children;
		}
		ArrayList<Object> ww = new ArrayList<Object>();
		Object[] contents2 = this.groupingContentProvider.contents;
		if (parent != null) {
			contents2 = parent.getChildren();
		}

		for (Object o : contents2) {

			DefaultPropertyMetadata md = (DefaultPropertyMetadata) p
					.getPropertyMetaData();

			boolean useAsLabelAsValue = false;
			ITextLabelProvider itl = null;

			Object vvv = md.get(DefaultPropertyMetadata.USE_LABEL_AS_VALUE);
			if (vvv instanceof Boolean && ((Boolean) vvv).booleanValue()) {
				itl = md.getAdapter(ITextLabelProvider.class);
				useAsLabelAsValue = true;
				
			}

			Object c = (Object) o;
			Object propertyValue = p.getValue(c);

			if (propertyValue == null) {
				propertyValue = "";
			}

			if (propertyValue instanceof Collection) {
				Collection<?> ca = (Collection<?>) propertyValue;
				if (ca.contains(value)) {
					ww.add(c);
				} else if (useAsLabelAsValue) {

					if (propertyValue == null || propertyValue.equals("")) {
						propertyValue = "<None>";
					}

					if (itl != null) {
						for (Object v : ca) {
							String tv = itl.getText(v);
							if (value.equals(tv)) {
								ww.add(c);
								break;
							}
						}
					}
				}
			} else if (propertyValue.equals(value)) {
				ww.add(c);
			} else if (useAsLabelAsValue) {
				if (itl != null) {

					if (propertyValue == null || propertyValue.equals("")) {
						propertyValue = "<None>";
					}

					String propVal = itl.getText(propertyValue);
					if (value.equals(propVal)) {
						ww.add(c);
					}
				}
			}
		}

		// System.out.println("filtering:" + (l1 - l0));
		children = ww.toArray(new Object[ww.size()]);
		return children;
	}

	public String getImageID() {
		return "com.onpositive.wiki.ui.image1";
	}

	public boolean isUsed(IViewGrouping v) {
		if (this.group.getId().equals(v.getId())) {
			return true;
		}
		if (parent != null) {
			return parent.isUsed(v);
		}
		return false;
	}

	int count;
	private ITextLabelProvider adapter;

	public void append(Object c) {
		count++;
	}

	public void customize(Object copy) {
		String id = group.getId();
		if (value != null && value.toString().length() > 0) {
//			((SimpleDocument) copy).putField(id, value); //TODO put value
		}
	}

	public <T> T getAdapter(Class<T> adapter) {
		if (adapter == ICanDrop.class) { //TODO d&d handling
			
		}
		return null;
	}

	public Object getFieldValue(String currentSorting) {
		if (currentSorting == null || currentSorting.length() == 0) {
			return this.value;
		}
		if (aggregates.containsKey(currentSorting)) {
			return aggregates.get(currentSorting);
		}
		Object calculateAggregate = AggregateCalculator
				.calculateAggregateWithProperty(getChildren(),
						groupingContentProvider.provider.getProperty(null,
								currentSorting), false);
		aggregates.put(currentSorting, calculateAggregate);
		return calculateAggregate;
	}

	public GroupNode getParent() {
		return parent;
	}

	public Collection<IUIFilter> toFilters() {
		ArrayList<IUIFilter> f = new ArrayList<IUIFilter>();
		fillFilters(f);
		return f;
	}

	private void fillFilters(ArrayList<IUIFilter> f) {
		if (this.parent != null) {
			parent.fillFilters(f);
		}
		BasicValueFilter e = new BasicValueFilter(group.getProperty());
		e.addValue(value);
		f.add(e);
	}

	private void fillClassification(
			ArrayList<ClassificationRealmPosition.Classification> f) {
		if (this.parent != null) {
			parent.fillClassification(f);
		}
		f.add(new Classification(group.getProperty().getId(), value));
	}

	public IRealmPosition toPosition() {
		ArrayList<ClassificationRealmPosition.Classification> m = new ArrayList<ClassificationRealmPosition.Classification>();
		IHasViews<?> parent2 = getRealmView().getParent();
		if (parent2 instanceof ClassificationRealmPosition) {
			ClassificationRealmPosition mm = (ClassificationRealmPosition) parent2;
			m.addAll(Arrays.asList(mm.getClassifications()));
			parent2 = mm.getParent();
		}
		fillClassification(m);
		ClassificationRealmPosition p = createClassificationPosition(
				parent2,
				m.toArray(new ClassificationRealmPosition.Classification[m
						.size()]));
		return p;
	}

	protected ClassificationRealmPosition createClassificationPosition(
			IHasViews<?> parent2, Classification[] array) {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * @return the childrenGrouping
	 */
	public IViewGrouping getChildrenGrouping() {
		return childrenGrouping;
	}

	/**
	 * @param childrenGrouping
	 *            the childrenGrouping to set
	 */
	public void setChildrenGrouping(IViewGrouping childrenGrouping) {
		this.childrenGrouping = childrenGrouping;
	}

	public boolean isSame(Object q) {
		if (q instanceof GroupNode) {
			return this.equals(q);
		}
		return false;
	}

	CodeAndMessage message;

	public CodeAndMessage getValidationStatus() {
		if (message != null) {
			return message;
		}
		Object[] children2 = getChildren();
		CodeAndMessage ma = CodeAndMessage.OK_MESSAGE;
//		for (Object m : children2) { //TODO content validation
//			CodeAndMessage validationStatus = m.getValidationStatus();
//			if (ma.compareTo(validationStatus) > 0) {
//				ma = validationStatus;
//			}
//		}
		return ma;
	}

}